﻿using System;
using MemoryPack;

namespace Hsenl {
    // 与 ActiveSelectorNode 同理
    [MemoryPackable]
    public partial class ActiveSequentialNode<TManager, TNode> : CompositeNode<TManager, TNode>
        where TManager : class, IBehaviorTree
        where TNode : class, INode {
        protected new void SetNodeStatus(INode node, NodeStatus status) {
            throw new NotImplementedException();
        }
        
        protected override bool OnNodeEvaluate() {
            return this.children.Count != 0;
        }

        protected override NodeStatus OnNodeTick() {
            var pos = 0;

            CONTINUE:

            if (pos >= this.children.Count) {
                this.position = 0;
                return NodeStatus.Success;
            }

            var child = this.children[pos];

            var status = child.EvaluateNode() ? child.TickNode() : NodeStatus.Continue;

            switch (status) {
                case NodeStatus.Continue: // 跳过, 在这里等同于成功
                case NodeStatus.Success:
                    base.SetNodeStatus(child, status);
                    pos++;
                    goto CONTINUE;

                case NodeStatus.Failure:
                    if (this.position > pos) {
                        base.SetNodeStatus(this.children[this.position], NodeStatus.Failure);
                    }

                    base.SetNodeStatus(child, status);
                    this.position = 0;
                    return NodeStatus.Failure;

                case NodeStatus.Running:
                    if (this.position > pos) {
                        base.SetNodeStatus(this.children[this.position], NodeStatus.Failure);
                    }

                    base.SetNodeStatus(child, status);
                    child.Run();
                    this.position = pos;
                    return NodeStatus.Running;

                case NodeStatus.Break:
                    if (this.position > pos) {
                        base.SetNodeStatus(this.children[this.position], NodeStatus.Failure);
                    }

                    base.SetNodeStatus(child, status);
                    this.position = 0;
                    // 正是由于这里不直接返回Break, 而是返回Continue, 所以它阻断了Break继续向上蔓延, 把Break的影响限制在了这条复合节点内部, 且由于返回的是continue, 所以不会影响上层的执行
                    return NodeStatus.Continue;

                case NodeStatus.Return:
                    if (this.position > pos) {
                        base.SetNodeStatus(this.children[this.position], NodeStatus.Failure);
                    }

                    base.SetNodeStatus(child, status);
                    this.position = 0;
                    return NodeStatus.Return; // 把Return返回给上层, 让它继续向上影响

                default:
                    throw new ArgumentOutOfRangeException($"OnNodeTick can't return {status}");
            }
        }
    }

    [MemoryPackable]
    public partial class ActiveSequentialNode : ActiveSequentialNode<IBehaviorTree, INode> { }
}